package main

import (
	"common/rtpengine"
	"common/rtpengine/rtp"
	"common/rtpengine/rtp/codecs"
	"common/util/reuse"
	"fmt"
	"github.com/pterm/pterm"
	"net"
	"os"
	"strings"
	"time"
	"xmediaEmu/pkg/media/amrwriter"
	"xmediaEmu/pkg/media/h264writer"
)

// 两条rtp流读取：音频和视频
var IpVideoRemoteAddr = "10.153.90.4:5004"
var IpAudioRemoteAddr = "10.153.90.4:5005"
var IpVideoLocalAddr = "10.153.90.4:6004"
var IpAudioLocalAddr = "10.153.90.4:6005"

var VideoFileNames = "guangdong.h264"
var AudioFileNames = "guangdongwb.amr"
var ReceiveTime = time.Second * 20

type AmrWbPayloader struct {
	codecs.AmrPayloader
}

func (p *AmrWbPayloader) Payload(mtu uint16, payload []byte) [][]byte {
	return p.PayloadAmrWbOctet(payload)
}

func main() {

	// 创建rtp流连接.
	//videoLeftAddr, _ := net.ResolveUDPAddr("udp", IpVideoLocalAddr)
	//videoRightAddr, _ := net.ResolveUDPAddr("udp", IpVideoRemoteAddr)
	//videoConn, err := net.DialUDP("udp", videoLeftAddr, videoRightAddr)
	conn, err := reuse.ListenPacket("udp", IpVideoRemoteAddr)
	if err != nil {
		pterm.FgRed.Printf("Listen the addr fail:%v... \n", err)
		os.Exit(-1)
	}
	videoConn := conn.(*net.UDPConn)
	// _ = conn.SetReadBuffer(5242880)
	defer videoConn.Close()
	pterm.FgWhite.Printf("Listen %s success!\n", IpVideoRemoteAddr)

	//trackVideo := rtpengine.NewTrackLocal("testTrack4321", IpVideoLocalAddr)
	//binds := rtpengine.SenderBinding{RightAddr: IpVideoRemoteAddr, PayloadType: 101, Payloader: &codecs.H264Payloader{}}
	//trackVideo.Bind(binds)
	//trackVideo.SetSamples(90000)
	//trackVideo.SetFrequence(25) // 25帧一秒.
	//if err := trackVideo.StartSession(rtpengine.Config{}); err != nil {
	//	fmt.Printf("trackVideo StartSession failed:%v\n. ", err)
	//	return
	//}
	//defer trackVideo.Close()
	//pterm.FgLightWhite.Printf("Dial %s success!\n", IpVideoRemoteAddr)
	//
	//trackAudio := rtpengine.NewTrackLocal("testTrack4321", IpAudioLocalAddr)
	//bindAudios := rtpengine.SenderBinding{RightAddr: IpAudioRemoteAddr, PayloadType: 97, Payloader: &AmrWbPayloader{}}
	//trackAudio.Bind(bindAudios)
	//trackAudio.SetSamples(16000)
	//if err := trackAudio.StartSession(rtpengine.Config{}); err != nil {
	//	fmt.Printf("trackVideo StartSession failed:%v\n. ", err)
	//	return
	//}
	//defer trackAudio.Close()
	//pterm.FgLightWhite.Printf("Dial %s success!\n", IpAudioRemoteAddr)

	// audioLeftAddr, _ := net.ResolveUDPAddr("udp", IpAudioLocalAddr)
	//audioRightAddr, _ := net.ResolveUDPAddr("udp", IpAudioRemoteAddr)
	//audioConn, err := net.DialUDP("udp", audioLeftAddr, audioRightAddr)
	conn, err = reuse.ListenPacket("udp", IpAudioRemoteAddr)
	if err != nil {
		pterm.FgRed.Printf("Listen the addr fail:%v... \n", err)
		os.Exit(-1)
	}
	audioConn := conn.(*net.UDPConn)
	// _ = conn.SetReadBuffer(5242880)
	defer audioConn.Close()
	pterm.FgWhite.Printf("Listen %s success!\n", IpAudioRemoteAddr)

	stopSync := make(chan interface{})
	go startVideoReceive(videoConn, stopSync)

	// create amr-wb file.
	// 解码器.
	amrWbFile, err := amrwriter.NewWb(AudioFileNames)
	if err != nil {
		panic(err)
	}
	defer amrWbFile.Close()
	amrhead := []byte{'#', '!', 'A', 'M', 'R', '-', 'W', 'B', '\n'}
	_ = amrWbFile.WriteFile(amrhead)

	//r, ssrc, err := trackAudio.AcceptStream()
	//if err != nil {
	//	fmt.Printf("trackAudio AcceptStream failed:%v\n. ", err)
	//	return
	//}
	//pterm.FgLightYellow.Printf("startVideoStream AcceptStream success, ssrc is:%d\n. ", ssrc)
	var currentBytes int
	var temp [1500]byte
	packet := rtp.Packet{}
	for {
		select {
		case <-stopSync:
			pterm.FgLightYellow.Println("start audio stop due to video stopped!")
			return
		//case <-timeTicker.C:
		//	if counter < 25 {
		//		l := 25 - counter
		//		for j:=counter; j < 25; j++ {
		//			if err = h264File.WriteRTP(&packet); err != nil {
		//				pterm.FgLightRed.Printf("receiveLocalMessage: WriteRTP copy last packet failed:%v\n. ", err)
		//			}
		//		}
		//		pterm.FgWhite.Printf("hWriter.WriteFile copy last packet done, count:%d . \n", l)
		//	}
		//	counter = 0
		default:
			// 无限循环.
			// 默认每次读到1200个字节.
			_ = audioConn.SetReadDeadline(time.Now().Add(5 * time.Second))
			receiveBytes, _, err := audioConn.ReadFromUDP(temp[0:])
			if err != nil {
				if strings.Contains(err.Error(), "timeout") {
					// normal read done
					pterm.FgRed.Printf("audioConn Timeout, the error is %s", err.Error())
					return
				} else {
					pterm.FgRed.Printf("audioConn Receive the rtp fail, the error is %s", err.Error())
					return
				}
			}

			if err := packet.Unmarshal(temp[0:receiveBytes]); err != nil {
				pterm.FgLightRed.Printf("audioConn: Unmarshal failed:%v\n. ", err)
			} else {
				if err = amrWbFile.WriteRTP(&packet); err != nil {
					pterm.FgLightRed.Printf("audioConn: WriteRTP failed:%v\n. ", err)
				} else {
					pterm.FgWhite.Printf("audioConn h264File.WriteFile count:%d done. \n", receiveBytes)
				}
			}

			currentBytes += len(packet.Payload)
			// counter++
			pterm.FgWhite.Printf("Receive amrWb success, the total length is %d\n", currentBytes)
		}
	}
}

// 读视频.
func startVideoReceive(videoConn *net.UDPConn, stop chan interface{}) {
	defer close(stop)
	ticker := time.NewTicker(ReceiveTime)
	// timeTicker := time.NewTicker(time.Second)
	h264File, err := h264writer.New(VideoFileNames)
	if err != nil {
		panic(err)
	}
	defer h264File.Close()

	var currentBytes int
	var temp [1500]byte
	packet := rtp.Packet{}
	for {
		select {
		case <-ticker.C:
			// 20 second 到了停止.
			// 直接停止
			pterm.FgLightYellow.Println("startVideoStream ticker stop!")
			return
		default:
			// 无限循环.
			// 默认每次读到1200个字节.
			_ = videoConn.SetReadDeadline(time.Now().Add(20 * time.Second))
			receiveBytes, _, err := videoConn.ReadFromUDP(temp[0:])
			if err != nil {
				if strings.Contains(err.Error(), "timeout") {
					// normal read done
					pterm.FgRed.Printf("startVideoStream Timeout, the error is %s", err.Error())
					return
				} else {
					pterm.FgRed.Printf("startVideoStream Receive the rtp fail, the error is %s", err.Error())
					return
				}
			}

			if err := packet.Unmarshal(temp[0:receiveBytes]); err != nil {
				pterm.FgLightRed.Printf("startVideoStream: Unmarshal failed:%v\n. ", err)
			} else {
				if err = h264File.WriteRTP(&packet); err != nil {
					pterm.FgLightRed.Printf("startVideoStream: WriteRTP failed:%v\n. ", err)
				} else {
					pterm.FgWhite.Printf("startVideoStream h264File.WriteFile count:%d done. \n", receiveBytes)
				}
			}

			currentBytes += receiveBytes
			pterm.FgWhite.Printf("startVideoStream Receive h264 success, the current lenth is %d\n", currentBytes)
		}
	}
}

// 读视频.
func startVideoStream(track *rtpengine.TrackLocal, stop chan interface{}) {
	defer close(stop)
	ticker := time.NewTicker(ReceiveTime)
	// timeTicker := time.NewTicker(time.Second)
	h264File, err := h264writer.New(VideoFileNames)
	if err != nil {
		panic(err)
	}
	defer h264File.Close()
	r, ssrc, err := track.AcceptStream()
	if err != nil {
		fmt.Printf("startVideoStream AcceptStream failed:%v\n. ", err)
		return
	}
	pterm.FgLightYellow.Printf("startVideoStream AcceptStream success, ssrc is:%d\n. ", ssrc)

	var currentBytes int
	var temp [1500]byte
	for {
		select {
		case <-ticker.C:
			// 20 second 到了停止.
			// 直接停止
			pterm.FgLightYellow.Println("startVideoStream ticker stop!")
			return
		default:
			// 无限循环.
			// 默认每次读到1200个字节.
			_ = r.SetReadDeadline(time.Now().Add(time.Second))
			packet, err := r.ReadRTP(temp[0:])
			if err != nil {
				if strings.Contains(err.Error(), "timeout") {
					// normal read done
					pterm.FgRed.Printf("startVideoStream Timeout, the error is %s", err.Error())
					return
				} else {
					pterm.FgRed.Printf("startVideoStream Receive the rtp fail, the error is %s", err.Error())
					return
				}
			}
			if err = h264File.WriteRTP(packet); err != nil {
				pterm.FgLightRed.Printf("startVideoStream h264File: WriteRTP failed:%v\n. ", err)
			} else {
				pterm.FgWhite.Printf("startVideoStream h264File.WriteFile Payload count:%d done. \n", len(packet.Payload))
			}
			currentBytes += len(packet.Payload)
			pterm.FgWhite.Printf("startVideoStream Receive h264 success, the current lenth is %d\n", currentBytes)
		}
	}
}
